#include <iostream>
#include <vector>
#include <string>
#include <fstream>

static size_t Split(const std::string &src, const std::string &sep, std::vector<std::string> *arry)
{
    int offset = 0;
    while (offset < src.size())
    {
        ssize_t pos = src.find(sep, offset);
        if (pos == std::string::npos)
        {
            arry->push_back(src.substr(offset));
            return arry->size();
        }

        if (offset == pos)
        {
            offset = pos + sep.size();
            continue;
        }

        arry->push_back(src.substr(offset, pos - offset));
        offset = pos + sep.size();
    }

    return arry->size();
}

static bool ReadFile(const std::string &filename, std::string *buf)
{
    // 打开文件
    std::ifstream Ifs(filename, std::ios::binary);
    if (Ifs.is_open() == false)
    {
        printf("OPEN %s FILE FAILED!!", filename.c_str());
        return false;
    }

    // 获取文件大小
    size_t fsize = 0;      // 用来存放文件内容的大小
    Ifs.seekg(0, Ifs.end); // 跳转到文件末尾
    fsize = Ifs.tellg();   // 获取当前指针位置相对于起始位置的偏移量，从末尾偏移刚好就是文件大小
    Ifs.seekg(0, Ifs.beg);

    // 将文件内容写入string
    buf->resize(fsize);
    Ifs.read(&((*buf)[0]), fsize);
    if (Ifs.good() == false)
    {
        printf("READ %s FILE FAILED!!", filename.c_str());
        Ifs.close();
        return false;
    }

    Ifs.close();
    return true;
}

static bool WriteFile(const std::string &filename, const std::string &buf)
{
    // std::ios::trunc代表每次打开文件都会清空文件内容
    std::ofstream Ofs(filename, std::ios::binary | std::ios::trunc);
    if (Ofs.is_open() == false)
    {
        printf("OPEN %s FILE FAILED!!", filename.c_str());
        return false;
    }

    Ofs.write(buf.c_str(), buf.size());
    if (Ofs.good() == false)
    {
        printf("READ %s FILE FAILED!!", filename.c_str());
        Ofs.close();
        return false;
    }

    Ofs.close();
    return true;
}

static std::string UrlEncode(const std::string url, bool convert_space_to_plus)
{
    std::string res;
    for (auto &c : url)
    {
        if (c == '.' || c == '-' || c == '_' || c == '~' || isalnum(c))
        {
            res += c;
            continue;
        }

        if (c == ' ' && convert_space_to_plus == true)
        {
            res += '+';
            continue;
        }

        //%x是十六进制，2代表显示为2位，0代表不足两位用0补齐，%%是给%转义，我们需要打印一个%出来
        char tmp[4] = {0};
        snprintf(tmp, 4, "%%%02x", c);
        res += tmp;
    }
    return res;
}

static char HEXTOI(char c)
{
    if (c >= 'a' && c <= 'z')
    {
        return c - 'a' + 10;
    }
    else if (c >= 'A' && c <= 'Z')
    {
        return c - 'A' + 10;
    }
    else if (c >= '0' && c <= '9')
    {
        return c - '0';
    }

    return -1;
}

static std::string UrlDecode(const std::string url, bool convert_space_to_plus)
{
    // 遇到了%，则将紧随其后的2个字符，转换为数字(char)
    std::string res;
    for (int i = 0; i < url.size(); i++)
    {
        if (url[i] == '+' && convert_space_to_plus == true)
        {
            res += ' ';
            continue;
        }

        if (url[i] == '%' && i + 2 < url.size())
        {
            char v1 = HEXTOI(url[i + 1]);
            char v2 = HEXTOI(url[i + 2]);
            char tmp = v1 * 16 + v2;
            res += tmp;
            i += 2;
            continue;
        }

        res += url[i];
    }
    return res;
}

int main()
{
    std::string str = "c+ +";
    std::string res = UrlEncode(str, true);
    std::cout << res << std::endl;
    std::string tmp = UrlDecode(res, true);
    std::cout << tmp << std::endl;

    /*
       std::string res;
       ReadFile("./eventfd.c", &res);
       WriteFile("./testfile", res);


       std::vector<std::string> res;
       std::string str = ".../ac/dgd///wewaaaa";

       Split(str, "/", &res);
       for (auto &s : res)
       {
           std::cout << s << std::endl;
       }
       */

    return 0;
}